#include "StdAfx.h"
#include "RibbonResultView.h"
#include "Resource.h"
#include <windows.h>
#include <UIRibbon.h>
#include <UIRibbonPropertyHelpers.h>
#include "RibbonOutputWindow.h"
#include <sstream>
#include <algorithm>
#include <propvarutil.h>

using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;


CRibbonResultView *CRibbonResultView::s_pRibbonResultView = 0;

CRibbonResultView::CRibbonResultView() : m_pRibbonOutputWindow(0), m_bUseSetValues(false), m_setBooleanValue(false), m_setNumericValue(0), m_setStringValue(L"")
{
	if (s_pRibbonResultView != 0)
		throw L"Only one result view is allowed";

	s_pRibbonResultView = this;

	m_commandTypeMap[UI_COMMANDTYPE_UNKNOWN] = L"Unknown";
	m_commandTypeMap[UI_COMMANDTYPE_GROUP] = L"Group";
	m_commandTypeMap[UI_COMMANDTYPE_ACTION] = L"Action";
	m_commandTypeMap[UI_COMMANDTYPE_ANCHOR] = L"Anchor";
	m_commandTypeMap[UI_COMMANDTYPE_CONTEXT] = L"Context";
	m_commandTypeMap[UI_COMMANDTYPE_COLLECTION] = L"Collection";
	m_commandTypeMap[UI_COMMANDTYPE_COMMANDCOLLECTION] = L"Command Collection";
	m_commandTypeMap[UI_COMMANDTYPE_DECIMAL] = L"Decimal";
	m_commandTypeMap[UI_COMMANDTYPE_BOOLEAN] = L"Boolean";
	m_commandTypeMap[UI_COMMANDTYPE_FONT] = L"Font";
	m_commandTypeMap[UI_COMMANDTYPE_RECENTITEMS] = L"Recent Items";
	m_commandTypeMap[UI_COMMANDTYPE_COLORANCHOR] = L"Color Anchor";
	m_commandTypeMap[UI_COMMANDTYPE_COLORCOLLECTION] = L"Color Collection";
}

void CRibbonResultView::AppendText(const wstring &text)
{
	if (m_pRibbonOutputWindow == 0)
		m_initText << text;
	else
		m_pRibbonOutputWindow->AppendText(text);
}

LPCWSTR CRibbonResultView::GetVerbName(UI_EXECUTIONVERB verb)
{
	switch (verb)
	{
	case UI_EXECUTIONVERB_EXECUTE:
		return L"Execute";
		
	case UI_EXECUTIONVERB_PREVIEW:
		return L"Preview";

	case UI_EXECUTIONVERB_CANCELPREVIEW:
		return L"Cancel Preview";
	}
	return L"";
}

HRESULT CRibbonResultView::Execute(UINT nCmdID,
		UI_EXECUTIONVERB verb, 
		__in_opt const PROPERTYKEY* key,
		__in_opt const PROPVARIANT* ppropvarValue,
		__in_opt IUISimplePropertySet* pCommandExecutionProperties)
{
	basic_stringstream<wchar_t> text;
	
	shared_ptr<CProperty> prop = m_propertyReader.Parse(key, ppropvarValue, pCommandExecutionProperties);
	text << L"Execute (" << GetVerbName(verb) << L")  ID:" << m_ribbonInfo->GetCommandNameById(nCmdID) << L"  Key Name:" << prop->GetPropertyKeyName() << L"  Value:" << prop->GetPropertyKeyValue() << endl;
	AppendText(text.str());


	return E_NOTIMPL;
}

STDMETHODIMP CRibbonResultView::UpdateProperty(UINT32 nCmdID, 
                                __in REFPROPERTYKEY key,
                                __in_opt  const PROPVARIANT *currentValue,
                                __out PROPVARIANT *newValue) 
{ 
	basic_stringstream<wchar_t> text;
	shared_ptr<CProperty> prop;
	HBITMAP hBitmap;

	if (currentValue == NULL || currentValue->vt == VT_EMPTY)
	{
		m_pUIFramework->GetUICommandProperty(nCmdID, key, newValue);
		prop = m_propertyReader.Parse(&key, newValue);
	}
	else
	{
		prop = m_propertyReader.Parse(&key, currentValue);
	}

	text << L"UpdateProperty -> ID:" << m_ribbonInfo->GetCommandNameById(nCmdID) << L"   Key Name:" << prop->GetPropertyKeyName();
	hBitmap = prop->GetBitmap();
	if (hBitmap == 0)
	{
		text<< L"   Current Value:" << prop->GetPropertyKeyValue();
	}
	
	AppendText(text.str());
	if (hBitmap)
	{
		AppendText(L"   ");
		m_pRibbonOutputWindow->InsertBitmap(hBitmap);
	}
	AppendText(L"\r\n");

	if (m_bUseSetValues)
	{
		return SetPropertyValues(key, newValue); 
	}
		
	return E_NOTIMPL;

}

HRESULT CRibbonResultView::SetPropertyValues(REFPROPERTYKEY key, PROPVARIANT *newValue) 
{ 
	HRESULT hr = E_NOTIMPL;
	
	switch (key.pid)
	{
	case VT_BOOL:
		return InitPropVariantFromBoolean(m_setBooleanValue, newValue);

	case VT_BSTR:
	case VT_LPWSTR:
		return InitPropVariantFromString(m_setStringValue.c_str(), newValue);

	case VT_DECIMAL:
		return InitPropVariantFromDouble(m_setNumericValue, newValue);

	case VT_I2:
		return InitPropVariantFromUInt16((USHORT)m_setNumericValue, newValue);
	
	case VT_I4:
		return InitPropVariantFromUInt32((UINT32)m_setNumericValue, newValue);

	case VT_INT:
		return InitPropVariantFromInt32((int)m_setNumericValue, newValue);
	}
	return hr;
}


LPCWSTR CRibbonResultView::TranslateType(UI_COMMANDTYPE typeID)  
{
	return m_commandTypeMap[typeID];
}

HRESULT CRibbonResultView::OnCreateUICommand(UINT32 nCmdID,
											 __in UI_COMMANDTYPE typeID,
											 __deref_out IUICommandHandler** ppCommandHandler) 
{
	basic_stringstream<wchar_t> text;

	text << L"OnCreateUICommand -> ID:" << m_ribbonInfo->GetCommandNameById(nCmdID) << L"   Type:" << TranslateType(typeID) << endl;
	AppendText(text.str());

	return QueryInterface(__uuidof(IUICommandHandler), (void**)ppCommandHandler);

}


HRESULT CRibbonResultView::OnViewChanged(UINT32 nViewID, __in UI_VIEWTYPE typeID, __in IUnknown* pView, UI_VIEWVERB verb, INT32 uReasonCode) 
{ 
	static PWCHAR verbText[] = { L"CREATE", L"DESTROY", L"SIZE", L"ERROR" };
    
	basic_stringstream<wchar_t> text;

	text << L"OnViewChanged -> ID:" << m_ribbonInfo->GetCommandNameById(nViewID) << L"   ReasonCode:" << uReasonCode;

	if (verb >= 0 && verb <= UI_VIEWVERB_ERROR)
		text << L"    Verb: " << verbText[verb];
	
	text << endl;
	AppendText(text.str());

	if (typeID == UI_VIEWTYPE_RIBBON && verb == UI_VIEWVERB_CREATE)
		pView->QueryInterface(__uuidof(IUIRibbon), (void **)&m_ribbon);

    return S_OK;  
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- free resources
//
//
LRESULT CALLBACK RibbonResultsWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
		
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;

	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		// TODO: Add any drawing code here...
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		delete CRibbonResultView::s_pRibbonResultView;
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}



HRESULT CRibbonResultView::OnAfterCreateRibbon(HWND hWnd, HINSTANCE hInstance)
{
	m_pRibbonOutputWindow = new CRibbonOutputWindow(hWnd, hInstance);
	m_hWnd = hWnd;
	BOOL bValid;
	IsValid(&bValid);
	UINT32 top = 10;
	if (bValid) GetRibbonHeight(&top);

	RECT rect;
	GetClientRect(hWnd, &rect);
	rect.top = top;
	m_pRibbonOutputWindow->SetSize(rect);
	
	m_pRibbonOutputWindow->AppendText(m_initText.str());
	m_initText.clear();

	const vector<int> &v = m_ribbonInfo->GetCommandIdsForContextualTabs();
	for_each(v.begin(), v.end(), tr1::bind(&CRibbonResultView::ShowContextualTab, this, _1, UI_CONTEXTAVAILABILITY_NOTAVAILABLE)); 
	
	return S_OK;
}

void CRibbonResultView::RegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= RibbonResultsWndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_RIBBONEXPLORER));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_RIBBONEXPLORER);
	wcex.lpszClassName	= RIBBONRESULTVIEW_WNDCLASS;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_RIBBONEXPLORER));
	RegisterClassEx(&wcex);
}


HRESULT CRibbonResultView::ShowContextualTab(int nCmdID, UI_CONTEXTAVAILABILITY UIContextAvailability)
{
	HRESULT hr = E_FAIL;

	PROPVARIANT ctxAvail;
	hr = UIInitPropertyFromUInt32(UI_PKEY_ContextAvailable, UIContextAvailability, &ctxAvail);
	if (FAILED(hr))
		return hr;
	hr = m_pUIFramework->SetUICommandProperty(nCmdID, UI_PKEY_ContextAvailable, ctxAvail);			
	return hr;
}

HRESULT CRibbonResultView::ShowContextMenu(int nCmdID)
{
	HRESULT hr;
	
	CComPtr<IUIContextualUI> pUIContextualUI; 
	hr = m_pUIFramework->GetView(nCmdID , __uuidof(pUIContextualUI), (void **)(&pUIContextualUI));
	if (FAILED(hr))
		return hr;
	RECT r;
	GetWindowRect(m_hWnd, &r);
	hr = pUIContextualUI->ShowAtLocation((r.left + r.right)/2, (r.bottom - r.top)/3 + r.top);
	return hr;
}

HRESULT CRibbonResultView::SetApplicationMode(INT32 applicationMode)
{
	HRESULT hr = m_pUIFramework->SetModes(applicationMode);
	return hr;
}

CRibbonResultView::~CRibbonResultView()
{
	if (s_pRibbonResultView == 0)
		return;
	s_pRibbonResultView = 0;

	for_each(m_closeHandlers.begin(), m_closeHandlers.end(), bind(&ICloseEvent::OnClose, _1));

	delete m_pRibbonOutputWindow;
}

HRESULT STDMETHODCALLTYPE CRibbonResultView::InvalidateUICommand( 
            UINT32 commandId,
            UI_INVALIDATIONS flags,
            /* [annotation][in] */ 
            __in_opt  const PROPERTYKEY *key)
{
	return m_pUIFramework->InvalidateUICommand(commandId, flags, key);
}

 
 HRESULT STDMETHODCALLTYPE CRibbonResultView::GetUICommandProperty( 
            UINT32 commandId,
            /* [in] */ REFPROPERTYKEY key,
            /* [out] */ PROPVARIANT *value)
        
 {
	return m_pUIFramework->GetUICommandProperty(commandId, key, value);
 }

 HRESULT STDMETHODCALLTYPE CRibbonResultView::SetUICommandProperty( 
            UINT32 commandId,
            /* [in] */ REFPROPERTYKEY key,
            /* [in] */ REFPROPVARIANT value)
        
 {
	return m_pUIFramework->SetUICommandProperty(commandId, key, value);
 }

HRESULT CRibbonResultView::LoadState()
{
  HRESULT hr = E_FAIL;
  if (m_stateStream)
  {
    LARGE_INTEGER liStart = {0, 0};
    ULARGE_INTEGER ulActual;
    hr = m_stateStream->Seek(liStart, STREAM_SEEK_SET, &ulActual);

	if (SUCCEEDED(hr))
	{
        hr = m_ribbon->LoadSettingsFromStream(m_stateStream);
	}
	if (SUCCEEDED(hr))
	{
		AppendText(L"Succeeded loading Ribbon state.\n");
	}
	else
	{
		AppendText(L"Error loading Ribbon state\n");
	}
  }
  return hr;
}



HRESULT CRibbonResultView::SaveState()
{
   HRESULT hr = E_FAIL; 

   if (m_stateStream) m_stateStream.Release();

   hr = CreateStreamOnHGlobal(NULL, TRUE, &m_stateStream);
   if (SUCCEEDED(hr))
   {
	   if (SUCCEEDED(hr))
	   {
	       hr = m_ribbon->SaveSettingsToStream(m_stateStream);
	   }
   }
   if (SUCCEEDED(hr))
   {
	   AppendText(L"The Ribbon State has been saved\n");
   }
   else
   {
	   AppendText(L"Error saving Ribbon state.");
	   if (hr == 0x80070490) //Element not found
           AppendText(L" Ribbon element is missing, check for UICC.EXE compiler warinings.");
	   AppendText(L"\n");
   }
   return hr;
}
